package com.example.exception;

import com.example.model.ErrorResponse;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

import java.sql.SQLException;

import static org.junit.jupiter.api.Assertions.*;

class SqlExceptionHandlerTest {

    private SqlExceptionHandler sqlExceptionHandler;

    @BeforeEach
    void setUp() {
        sqlExceptionHandler = new SqlExceptionHandler();
    }

    @Test
    void testHandleConfigurationErrorByMessage() {
        // 测试通过错误消息识别配置错误
        SQLException ex = new SQLException("Access denied for user 'root'@'localhost'");
        ResponseEntity<ErrorResponse> response = sqlExceptionHandler.handleSqlException(ex);

        assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
        assertNotNull(response.getBody());
        assertEquals("DB_CONFIG_ERROR", response.getBody().getCode());
        assertEquals("数据库配置信息有误，请检查连接参数", response.getBody().getMessage());
    }

    @Test
    void testHandleConfigurationErrorBySqlState() {
        // 测试通过 SQLState 识别配置错误
        SQLException ex = new SQLException("Authentication failed", "28000", 1045);
        ResponseEntity<ErrorResponse> response = sqlExceptionHandler.handleSqlException(ex);

        assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
        assertNotNull(response.getBody());
        assertEquals("DB_CONFIG_ERROR", response.getBody().getCode());
        assertEquals("数据库配置信息有误，请检查连接参数", response.getBody().getMessage());
    }

    @Test
    void testHandleConfigurationErrorByAccessRule() {
        // 测试通过访问规则错误识别配置错误
        SQLException ex = new SQLException("Access denied for database 'test'", "42000", 1044);
        ResponseEntity<ErrorResponse> response = sqlExceptionHandler.handleSqlException(ex);

        assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
        assertNotNull(response.getBody());
        assertEquals("DB_CONFIG_ERROR", response.getBody().getCode());
        assertEquals("数据库配置信息有误，请检查连接参数", response.getBody().getMessage());
    }

    @Test
    void testHandleConfigurationErrorByUnknownDatabase() {
        // 测试通过未知数据库错误识别配置错误
        SQLException ex = new SQLException("Unknown database 'nonexistent'");
        ResponseEntity<ErrorResponse> response = sqlExceptionHandler.handleSqlException(ex);

        assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
        assertNotNull(response.getBody());
        assertEquals("DB_CONFIG_ERROR", response.getBody().getCode());
        assertEquals("数据库配置信息有误，请检查连接参数", response.getBody().getMessage());
    }

    @Test
    void testHandleConfigurationErrorByBadHandshake() {
        // 测试通过握手失败错误识别配置错误
        SQLException ex = new SQLException("Bad handshake");
        ResponseEntity<ErrorResponse> response = sqlExceptionHandler.handleSqlException(ex);

        assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
        assertNotNull(response.getBody());
        assertEquals("DB_CONFIG_ERROR", response.getBody().getCode());
        assertEquals("数据库配置信息有误，请检查连接参数", response.getBody().getMessage());
    }

    @Test
    void testHandleConnectionErrorByMessage() {
        // 测试通过错误消息识别连接错误
        SQLException ex = new SQLException("Connection refused");
        ResponseEntity<ErrorResponse> response = sqlExceptionHandler.handleSqlException(ex);

        assertEquals(HttpStatus.SERVICE_UNAVAILABLE, response.getStatusCode());
        assertNotNull(response.getBody());
        assertEquals("DB_CONNECTION_ERROR", response.getBody().getCode());
        assertEquals("服务端连接不通，请检查网络连通性", response.getBody().getMessage());
    }

    @Test
    void testHandleConnectionErrorByTimeout() {
        // 测试通过超时错误识别连接错误
        SQLException ex = new SQLException("Connection timed out");
        ResponseEntity<ErrorResponse> response = sqlExceptionHandler.handleSqlException(ex);

        assertEquals(HttpStatus.SERVICE_UNAVAILABLE, response.getStatusCode());
        assertNotNull(response.getBody());
        assertEquals("DB_CONNECTION_ERROR", response.getBody().getCode());
        assertEquals("服务端连接不通，请检查网络连通性", response.getBody().getMessage());
    }

    @Test
    void testHandleConnectionErrorBySqlState() {
        // 测试通过 SQLState 识别连接错误
        SQLException ex = new SQLException("Communications link failure", "08001", 0);
        ResponseEntity<ErrorResponse> response = sqlExceptionHandler.handleSqlException(ex);

        assertEquals(HttpStatus.SERVICE_UNAVAILABLE, response.getStatusCode());
        assertNotNull(response.getBody());
        assertEquals("DB_CONNECTION_ERROR", response.getBody().getCode());
        assertEquals("服务端连接不通，请检查网络连通性", response.getBody().getMessage());
    }

    @Test
    void testHandleConnectionErrorByNetwork() {
        // 测试通过网络错误识别连接错误
        SQLException ex = new SQLException("Network is unreachable");
        ResponseEntity<ErrorResponse> response = sqlExceptionHandler.handleSqlException(ex);

        assertEquals(HttpStatus.SERVICE_UNAVAILABLE, response.getStatusCode());
        assertNotNull(response.getBody());
        assertEquals("DB_CONNECTION_ERROR", response.getBody().getCode());
        assertEquals("服务端连接不通，请检查网络连通性", response.getBody().getMessage());
    }

    @Test
    void testHandleConnectionErrorByHost() {
        // 测试通过主机错误识别连接错误
        SQLException ex = new SQLException("Host is unreachable");
        ResponseEntity<ErrorResponse> response = sqlExceptionHandler.handleSqlException(ex);

        assertEquals(HttpStatus.SERVICE_UNAVAILABLE, response.getStatusCode());
        assertNotNull(response.getBody());
        assertEquals("DB_CONNECTION_ERROR", response.getBody().getCode());
        assertEquals("服务端连接不通，请检查网络连通性", response.getBody().getMessage());
    }

    @Test
    void testHandleGenericError() {
        // 测试通用错误，应该按连接错误处理
        SQLException ex = new SQLException("Some unknown error occurred", "HY000", 0);
        ResponseEntity<ErrorResponse> response = sqlExceptionHandler.handleSqlException(ex);

        assertEquals(HttpStatus.SERVICE_UNAVAILABLE, response.getStatusCode());
        assertNotNull(response.getBody());
        assertEquals("DB_CONNECTION_ERROR", response.getBody().getCode());
        assertEquals("服务端连接不通，请检查网络连通性", response.getBody().getMessage());
    }

    @Test
    void testHandleNullMessage() {
        // 测试空消息的情况
        SQLException ex = new SQLException(null, "HY000", 0);
        ResponseEntity<ErrorResponse> response = sqlExceptionHandler.handleSqlException(ex);

        assertEquals(HttpStatus.SERVICE_UNAVAILABLE, response.getStatusCode());
        assertNotNull(response.getBody());
        assertEquals("DB_CONNECTION_ERROR", response.getBody().getCode());
        assertEquals("服务端连接不通，请检查网络连通性", response.getBody().getMessage());
    }

    @Test
    void testHandleNullSqlState() {
        // 测试空 SQLState 的情况
        SQLException ex = new SQLException("Some error message");
        ResponseEntity<ErrorResponse> response = sqlExceptionHandler.handleSqlException(ex);

        assertEquals(HttpStatus.SERVICE_UNAVAILABLE, response.getStatusCode());
        assertNotNull(response.getBody());
        assertEquals("DB_CONNECTION_ERROR", response.getBody().getCode());
        assertEquals("服务端连接不通，请检查网络连通性", response.getBody().getMessage());
    }
} 